#include "GameObject.h"
#include "IComponent.h"
#include "..\Managers\GameObjectManager.h"

void GameObject::addComponent(IComponent* p_component)
{
	addInternal(p_component, p_component->getType());

	//Add to family type
	if(p_component->getType() != p_component->getFamilyType())
	{
		addInternal(p_component, p_component->getFamilyType());
	}	p_component->setOwner(this);
}

IComponent* GameObject::getComponent(const std::string& p_type)
{
	return getComponent(p_type, 0);
}
IComponent* GameObject::getComponent(const std::string& p_type, unsigned int p_index)
{
	ComponentMap::iterator itr = m_components.find(p_type);
	if(itr != m_components.end())
	{
		ComponentList* list = itr->second;
		if(list != nullptr)
		{
			if(p_index < list->size())
			{
				IComponent* comp = (*list)[p_index];
				return comp;
			}
		}
	}
	return nullptr;
}

void GameObject::removeComponent(IComponent* p_component)
{
	m_removeList.push_back(p_component);
	/*removeInternal(p_component, p_component->getType());

	//Remove from family type
	if(p_component->getType() != p_component->getFamilyType())
	{
		removeInternal(p_component, p_component->getFamilyType());
	}
	delete p_component; //Manager?
	*/
}


void GameObject::clearComponents()
{
	for(auto it = m_components.begin(); it != m_components.end(); it++)
	{
		for(auto it2 = (*it).second->begin(); it2 != (*it).second->end(); it2++)
		{
			delete (*it2);
			(*it2) = nullptr;
		}
		it->second->clear();
		delete it->second;
	}
	m_components.clear();
}

void GameObject::addInternal(IComponent* p_component, const std::string& p_type)
{
	ComponentMap::iterator itr = m_components.find(p_type);
	ComponentList* list = nullptr;
	if(itr == m_components.end())
	{
		list = new ComponentList();
		m_components.insert(std::pair< std::string, ComponentList*>(p_type, list));
	}
	else
	{
		if(itr->second == nullptr)
		{
			list = new ComponentList();
			m_components[p_type] = list;
		}
		else
		{
			list = itr->second;
		}
	}
	list->push_back(p_component);
}

void GameObject::removeInternal(IComponent* p_component, const std::string& p_type)
{
	ComponentMap::iterator itr = m_components.find(p_type);
	ComponentList* list = nullptr;
	int found = -1;
	if(itr != m_components.end())
	{
		list = itr->second;
		if(list != nullptr)
		{
			for(unsigned int i = 0; i < list->size(); ++i)
			{
				if((*list)[i] == p_component)
				{
					found = i;
					break;
				}
			}
			if(found != -1)
			{
				if(found != list->size()-1)
				{
					(*list)[found] = list->back();
				}
				list->pop_back();
				
				//Clean the map
				if(list->empty())
				{
					itr->second = nullptr;
					m_components.erase(itr);
					delete list;
				}
			}
		}
		else
		{
			m_components.erase(itr);
		}
	}
}

void GameObject::initComponents()
{
	for(auto it = m_components.begin(); it != m_components.end(); it++)
	{
		for(auto it2 = (*it).second->begin(); it2 != (*it).second->end(); it2++)
		{
			(*it2)->init();
		}
	}
}

void GameObject::update(const GameTime& p_gameTime)
{
	if (!m_removeList.empty())
	{
		for (auto it = m_removeList.begin(); it != m_removeList.end(); it++)
		{
			remove((*it));
		}
		m_removeList.clear();
	}

	for(auto it = m_components.begin(); it != m_components.end(); it++)
	{
		for(auto it2 = (*it).second->begin(); it2 != (*it).second->end(); it2++)
		{
			(*it2)->update(p_gameTime);
		}
	}
}

void GameObject::removeMe()
{
	if (m_gameObjectManager != nullptr)
	{
		m_gameObjectManager->removeGameObject(this);
	}
}

void GameObject::remove(IComponent* p_component)
{
	for(auto it = m_components.begin(); it != m_components.end(); it++)
	{
		for(auto it2 = (*it).second->begin(); it2 != (*it).second->end(); it2++)
		{
			if ((*it2) == p_component)
			{
				(*it).second->erase(it2);
				delete p_component;
				break;
			}
		}
	}
}